#include <mcp/client/simple_client.h>
#include <iostream>
#include <string>

using namespace mcp;
using namespace mcp::client;

int main(int argc, char* argv[]) {
    try {
        std::string transport_url = "stdio://";

        if (argc > 1) {
            transport_url = argv[1];
        }

        std::cout << "MCP C++ Simple Client Example\n";
        std::cout << "==============================\n\n";
        std::cout << "Transport URL: " << transport_url << "\n\n";

        // Create client
        ClientConfig config{
            .name = "MCP C++ Simple Client",
            .version = "1.0.0",
            .timeout_seconds = 10
        };

        auto client = create_simple_client(transport_url, config);

        // Set up handlers
        client->set_notification_handler([](const std::string& method, const json::Value& params) {
            std::cout << "Notification: " << method << "\n";
        });

        client->set_error_handler([](const std::string& error) {
            std::cerr << "Error: " << error << "\n";
        });

        // Connect to server
        std::cout << "Connecting to server...\n";
        if (!client->connect()) {
            std::cerr << "Failed to connect to server\n";
            return 1;
        }

        std::cout << "Connected successfully!\n\n";

        // Get server info
        auto server_info = client->get_server_info();
        if (server_info) {
            std::cout << "Server Info:\n";
            std::cout << "  Name: " << (*server_info)["name"].as_string() << "\n";
            std::cout << "  Version: " << (*server_info)["version"].as_string() << "\n";
            if ((*server_info).contains("description")) {
                std::cout << "  Description: " << (*server_info)["description"].as_string() << "\n";
            }
        } else {
            std::cout << "Failed to get server info: " << server_info.error() << "\n";
        }

        std::cout << "\n";

        // List tools
        auto tools = client->list_tools();
        if (tools) {
            std::cout << "Available Tools (" << tools->size() << "):\n";
            for (const auto& tool : *tools) {
                std::cout << "  - " << tool.name << ": " << tool.description << "\n";
            }
        } else {
            std::cout << "Failed to list tools: " << tools.error() << "\n";
        }

        std::cout << "\n";

        // List resources
        auto resources = client->list_resources();
        if (resources) {
            std::cout << "Available Resources (" << resources->size() << "):\n";
            for (const auto& resource : *resources) {
                std::cout << "  - " << resource.uri << ": " << resource.name << "\n";
            }
        } else {
            std::cout << "Failed to list resources: " << resources.error() << "\n";
        }

        std::cout << "\n";

        // List prompts
        auto prompts = client->list_prompts();
        if (prompts) {
            std::cout << "Available Prompts (" << prompts->size() << "):\n";
            for (const auto& prompt : *prompts) {
                std::cout << "  - " << prompt.name << ": "
                         << (prompt.description ? *prompt.description : "No description") << "\n";
            }
        } else {
            std::cout << "Failed to list prompts: " << prompts.error() << "\n";
        }

        std::cout << "\n";

        // Call a tool (if available)
        if (tools && !tools->empty()) {
            const auto& first_tool = tools->front();
            std::cout << "Testing tool: " << first_tool.name << "\n";

            // Try to call with sample arguments
            auto args = json::Value::object({
                {"a", 10},
                {"b", 20}
            });

            auto result = client->call_tool(first_tool.name, args);
            if (result) {
                std::cout << "Tool result: " << result->serialize() << "\n";
            } else {
                std::cout << "Tool call failed: " << result.error() << "\n";
            }
        }

        std::cout << "\n";

        // Read a resource (if available)
        if (resources && !resources->empty()) {
            const auto& first_resource = resources->front();
            std::cout << "Testing resource: " << first_resource.uri << "\n";

            auto content = client->read_resource(first_resource.uri);
            if (content) {
                std::cout << "Resource content:\n";
                for (const auto& block : content->contents) {
                    if (auto text = std::dynamic_pointer_cast<TextContent>(block)) {
                        std::cout << "  " << text->text << "\n";
                    }
                }
            } else {
                std::cout << "Resource read failed: " << content.error() << "\n";
            }
        }

        std::cout << "\n";

        // Call a prompt (if available)
        if (prompts && !prompts->empty()) {
            const auto& first_prompt = prompts->front();
            std::cout << "Testing prompt: " << first_prompt.name << "\n";

            auto args = json::Value::object({
                {"operation", "addition"},
                {"a", 15},
                {"b", 25}
            });

            auto messages = client->call_prompt(first_prompt.name, args);
            if (messages) {
                std::cout << "Prompt messages (" << messages->size() << "):\n";
                for (const auto& message : *messages) {
                    std::cout << "  [" << static_cast<int>(message.role) << "] ";
                    if (auto text = std::dynamic_pointer_cast<TextContent>(message.content)) {
                        std::cout << text->text;
                    }
                    std::cout << "\n";
                }
            } else {
                std::cout << "Prompt call failed: " << messages.error() << "\n";
            }
        }

        // Send a log message
        client->send_log(LogLevel::Info, "Hello from client!");

        std::cout << "\nPress Enter to disconnect...\n";
        std::cin.get();

        // Disconnect
        client->disconnect();
        std::cout << "Disconnected from server.\n";

    } catch (const std::exception& e) {
        std::cerr << "Error: " << e.what() << "\n";
        return 1;
    }

    return 0;
}